package io.github.frailty9.crserver.utils

import org.jetbrains.annotations.TestOnly

class SnowflakeIdWorker(
    private val workerId: Long,
    private val datacenterId: Long
) {
    // Epoch: 2025-10-12 13:15:08 UTC
    private val epoch = 1760256908637L

    private companion object {
        private const val WORKER_ID_BITS = 5
        private const val DATACENTER_ID_BITS = 5
        private const val SEQUENCE_BITS = 12

        private const val MAX_WORKER_ID = (1L shl WORKER_ID_BITS) - 1
        private const val MAX_DATACENTER_ID = (1L shl DATACENTER_ID_BITS) - 1

        private const val WORKER_ID_SHIFT = SEQUENCE_BITS
        private const val DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS
        private const val TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS
        private const val SEQUENCE_MASK = (1L shl SEQUENCE_BITS) - 1
    }

    private var sequence = 0L
    private var lastTimestamp = -1L

    init {
        require(workerId in 0..MAX_WORKER_ID) {
            "workerId must be between 0 and $MAX_WORKER_ID"
        }
        require(datacenterId in 0..MAX_DATACENTER_ID) {
            "datacenterId must be between 0 and $MAX_DATACENTER_ID"
        }
    }

    @Synchronized
    fun nextId():Long {
        return nextId(System.currentTimeMillis())
    }

    /**
     * 生成下一个ID
     * 注意, 该方法本该为私有方法, 为了单元测试所以改为公开方法, 请勿在生成环境中使用
     * @param timestamp 时间戳
     * @return ID
     */
    @TestOnly
    @Synchronized
    fun nextId(timestamp: Long): Long {
        var timestamp = timestamp

        require(timestamp >= epoch) { "System clock is before epoch!" }

        if (timestamp < lastTimestamp) {
            val offset = lastTimestamp - timestamp
            if (offset > 5) { // 容忍 5ms 内回拨
                throw RuntimeException("Clock moved backwards: $offset ms")
            }
            // 等待时钟追上
            while (System.currentTimeMillis() <= lastTimestamp) {
                // 避免 busy wait
                Thread.sleep(1)
            }
            timestamp = System.currentTimeMillis()
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) and SEQUENCE_MASK
            if (sequence == 0L) {
                // 序列号用完，等待下一毫秒
                while (System.currentTimeMillis() <= lastTimestamp) {
                    Thread.sleep(1)
                }
                timestamp = System.currentTimeMillis()
            }
        } else {
            sequence = 0L // 重置序列号
        }

        lastTimestamp = timestamp

        return ((timestamp - epoch) shl TIMESTAMP_LEFT_SHIFT) or
                (datacenterId shl DATACENTER_ID_SHIFT) or
                (workerId shl WORKER_ID_SHIFT) or
                sequence
    }

    // ============= ID反解析 =============
    /**
     * 通过ID反解析生成时间戳
     * @param id ID
     * @return 整型时间戳
     */
    fun parseTimestamp(id: Long): Long {
        return (id shr TIMESTAMP_LEFT_SHIFT) + epoch
    }

    /**
     * 通过ID反解析生成workerId
     * @param id ID
     * @return workerId
     */
    fun parseWorkerId(id: Long): Long {
        return (id shr WORKER_ID_SHIFT) and MAX_WORKER_ID
    }

    /**
     * 通过ID反解析生成datacenterId
     * @param id ID
     * @return datacenterId
     */
    fun parseDatacenterId(id: Long): Long {
        return (id shr DATACENTER_ID_SHIFT) and MAX_DATACENTER_ID
    }

    /**
     * 通过ID反解析生成序列号
     * @param id ID
     * @return 序列号
     */
    fun parseSequence(id: Long): Long {
        return id and SEQUENCE_MASK
    }
}